//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "type_traits.h"
#include "string.h"
#include "vector.h"

#define FC_DEFAULT_DELIMITERS " \t\n\r"

#ifdef _MSC_VER
	#pragma warning ( push )
	#pragma warning ( disable : 4127 )
#endif


FC_NAMESPACE_BEGIN


template <class StringType = string, bool KeepStringLiterals = true>
class basic_tokenizer
{
public:
	typedef size_t											size_type;
	typedef StringType										string_type;
	typedef basic_tokenizer<StringType,KeepStringLiterals>	this_type;
	typedef vector<string_type>								array_string_type;

	basic_tokenizer( const string_type& str = string_type(), const string_type& delimiters = FC_DEFAULT_DELIMITERS )
		: _index(0), _string(str), _delimiters(delimiters)
		{
		}
	basic_tokenizer( const this_type& t ) : _index(t._index), _string(t._string), _delimiters(t._delimiters)
		{
		}

	size_t get_position() const { return _index; }

	string_type& get_string() { return _string; }
	const string_type& get_string() const { return _string; }

	string_type& get_delimiters() { return _delimiters; }
	const string_type& get_delimiters() const { return _delimiters; }

	void set_string( const string_type& str )
	{
		_index = 0;
		_string = str;
	}

	void set_delimiters( const string_type& delimiters ) { _delimiters = delimiters; }
	void set_position( size_t pos )
	{
		_index = pos < _string.size() ? pos : _string.size();
	}
	
	bool next( string_type& token )
	{
		return get_token( _string, _delimiters, _index, token );
	}

	static bool get_token( const string_type& str, const string_type& delimiters, size_type& index, string_type& token )
	{
		size_t begin_index;
		size_t end_index;

		begin_index = str.find_first_not_of( delimiters, index );

		if( begin_index == string_type::npos ) 
			return false;

		if(KeepStringLiterals && str[ begin_index ] == '"' ) //string literal can contain delimiters
		{
			end_index = str.find_first_of( '"', begin_index + 1 );
			if( end_index < str.size() )
				++end_index;
		}
		else
		{
			end_index = str.find_first_of( delimiters, begin_index + 1 );
		}

		if( end_index == string_type::npos )
			end_index = str.size();

		FC_ASSERT(end_index >= begin_index);

		index = end_index;
		token.assign( &str[ begin_index ], end_index - begin_index );

		return true;
	}

	template<class ContainerType>
	static void tokenize( ContainerType &tokens, const string_type& str, const string_type& delimiters = FC_DEFAULT_DELIMITERS )
	{
		string_type token;
		size_t index = 0;

		while( get_token(str, delimiters, index, token) )
			tokens.push_back( token );
	}

protected:
	size_type _index;
	string_type _string;
	string_type _delimiters;

};


typedef basic_tokenizer<fc::string, true> tokenizer;



FC_NAMESPACE_END

#ifdef _MSC_VER
	#pragma warning ( pop )
#endif

